package com.qf.controller;

import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.recipes.locks.InterProcessMutex;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.PostConstruct;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 模拟高并发 秒杀场景  牙刷
 *
 * @author lixu
 */
@RestController
@RequestMapping("/sec")
public class SeckillController {

    //商品 ： item:款   本地锁
/*    private static Map<String,Integer> itemsMap = new HashMap<>();
    //订单
    private static Map<String,Integer> ordersMap = new HashMap<>();*/

    private Lock lock = new ReentrantLock();

/*    static {
        itemsMap.put("牙刷",10000);
        ordersMap.put("牙刷",0);
    }*/

    @Autowired
    private RedisTemplate redisTemplate; //官方 AXxxfdsyashua
    @Autowired
    private CuratorFramework cf;

    @PostConstruct
    public void abc() {
        redisTemplate.opsForValue().set("yashua", 10000);
        redisTemplate.opsForValue().set("dingdan", 0);
    }

    /**
     * redis  实现分布式锁
     */
    @GetMapping("redis/kill")
    public String rediskill() throws Exception {
        Boolean isExist = null;
        /**
         * 第一种 ： 自旋锁
         */
        do {
            //2,TimeUnit.SECONDS 设置过期时间 为了防止死锁
            isExist = redisTemplate.opsForValue().setIfAbsent("lock", "123",8,TimeUnit.SECONDS); //过期不候的锁
        } while(!isExist);// 乐观锁：底层就是CAS  version = 10

        /**
         * 第二种 ： 自旋锁
         */
        //无限循环 + 过期不候的锁 == 不见不散的锁
/*        while (true) {//无限循环
            //获取锁   setnx   返回值 0 ： false   1:true
            Boolean isExist = redisTemplate.opsForValue().setIfAbsent("lock", "123"); //过期不候的锁
            if (isExist) {
                //获取到锁
                break;
            }
        }*/
        //获取到了锁
        String item;
        item = "牙刷";
        //秒杀我们的牙刷
        Integer num = (Integer) redisTemplate.opsForValue().get("yashua");
        if (num <= 0) {
            return "商品库存数不足！！！";
        }
        num--; //
        //Thread.sleep(100);//代码 中就一些时候比较 慢
        //更新牙刷的数量
        redisTemplate.opsForValue().set("yashua", num);
        //生产订单
        Integer orderNum = (Integer) redisTemplate.opsForValue().get("dingdan");
        orderNum++;
        redisTemplate.opsForValue().set("dingdan", orderNum);
        //解锁  删除 lock
        redisTemplate.delete("lock");
        //3. 返回信息
        return "抢购成功！！！" + item + "： 剩余库存数为 - "
                + redisTemplate.opsForValue().
                get("yashua") + "，订单数为 - "
                + redisTemplate.opsForValue().
                get("dingdan");

    }

    /**
     * zookeeper 实现分布式锁
     */
    @GetMapping("zookeeper/kill")
    public String zookeeperkill() throws Exception {

        //自己会创建 /lock临时有序节点
        InterProcessMutex interProcessMutex = new InterProcessMutex(cf, "/lock");
        //分布式锁  上锁
        interProcessMutex.acquire();//不见不散的锁  不获取到锁我就不走了  堵塞

        String item;
        item = "牙刷";
        //秒杀我们的牙刷
        Integer num = (Integer) redisTemplate.opsForValue().get("yashua");
        if (num <= 0) {
            interProcessMutex.release();
            return "商品库存数不足！！！";
        }
        num--; //
        //Thread.sleep(100);//代码 中就一些时候比较 慢
        //更新牙刷的数量
        redisTemplate.opsForValue().set("yashua", num);
        //生产订单
        Integer orderNum = (Integer) redisTemplate.opsForValue().get("dingdan");
        orderNum++;
        redisTemplate.opsForValue().set("dingdan", orderNum);

        //解锁  释放锁
        interProcessMutex.release();
        //3. 返回信息
        return "抢购成功！！！" + item + "： 剩余库存数为 - "
                + redisTemplate.opsForValue().

                get("yashua") + "，订单数为 - "
                + redisTemplate.opsForValue().

                get("dingdan");


    }


    /**
     * 开始秒杀
     */
    @GetMapping("/kill")
    public String kill() throws Exception {
        lock.lock();
        String item;
        try {
            item = "牙刷";
            //秒杀我们的牙刷
            Integer num = (Integer) redisTemplate.opsForValue().get("yashua");
            if (num <= 0) {
                return "商品库存数不足！！！";
            }
            num--; //
            //Thread.sleep(100);//代码 中就一些时候比较 慢
            //更新牙刷的数量
            redisTemplate.opsForValue().set("yashua", num);
            //生产订单
            Integer orderNum = (Integer) redisTemplate.opsForValue().get("dingdan");
            orderNum++;
            redisTemplate.opsForValue().set("dingdan", orderNum);
        } finally {
            lock.unlock();
        }
        //3. 返回信息
        return "抢购成功！！！" + item + "： 剩余库存数为 - "
                + redisTemplate.opsForValue().get("yashua") + "，订单数为 - "
                + redisTemplate.opsForValue().get("dingdan");
    }

    public static void main(String[] args) {
        System.out.println("192.168.200.129".hashCode()%3);//=2
        System.out.println("192.168.200.130".hashCode()%3);//=2
        System.out.println("192.168.200.131".hashCode()%3);//=1
    }
}
